/* Copyright 2009
 *
 * This program and the accompanying materials
 * are made available under the terms of the
 * Eclipse Public License v1.0 which accompanies
 * this distribution, and is available at
 *
 * 		http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in
 * writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
 * OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * Contributors:
 * 	   IBM Corporation - initial API and implementation for JDT/DLTK
 *     Sean W. Quinn - initial adoption for use with PHP from various sources.
 */
package org.eclipse.php.internal.formatter;

import java.io.IOException;
import java.io.LineNumberReader;
import java.io.Reader;
import java.io.StringReader;
import java.util.Map;

import org.eclipse.dltk.formatter.AbstractScriptFormatter;
import org.eclipse.dltk.formatter.FormatterDocument;
import org.eclipse.dltk.ui.formatter.FormatterException;
import org.eclipse.dltk.ui.formatter.FormatterSyntaxProblemException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.php.internal.core.compiler.ast.parser.AbstractPHPSourceParser;
import org.eclipse.php.internal.core.compiler.ast.parser.PHPSourceParserFactory;
import org.eclipse.php.internal.core.parser.PHPParserResult;
import org.eclipse.text.edits.TextEdit;

/**
 * @author Sean W. Quinn (swquinn@gmail.com)
 *
 */
public class PHPFormatter extends AbstractScriptFormatter {

  protected static final String[] INDENTING = {};

  protected static final String[] BLANK_LINES = {};

  private final String lineDelimiter;

  public PHPFormatter(String lineDelimiter, Map preferences) {
    super(preferences);
    this.lineDelimiter = lineDelimiter;
  }

  @Override
public int detectIndentationLevel(IDocument document, int offset) {
    final String input = document.get();
    final PHPParserResult result;
    try {
      final AbstractPHPSourceParser parser = PHPSourceParserFactory.createParser(null);
      final StringReader reader = new StringReader(document.get());
      parser.parse(reader, null);
    }
    catch (FormatterSyntaxProblemException ex) {
      // ignore?
    }
    catch (Exception ex) {
      // ignore... for now
    }

    //      final PHPFormatterNodeBuilder builder = new PHPFormatterNodeBuilder();
    //      final FormatterDocument fDocument = createDocument(input);
    //      IFormatterContainerNode root = builder.build(result, fDocument);
    //      new PHPFormatterNodeRewriter(result).rewrite(root);
    //      final IFormatterContext context = new PHPFormatterContext(0);
    //      FormatterIndentDetector detector = new FormatterIndentDetector(offset);
    //      try {
    //        root.accept(context, detector);
    //        return detector.getLevel();
    //      }
    //      catch (Exception e) {
    //        // ignore
    //      }
    //    }
    //    catch (FormatterSyntaxProblemException e) {
    //      // ignore
    //    }
    // TODO keep current indent
    return 0;
  }

  public TextEdit format(String source, int offset, int length, int indent) throws FormatterException {
    //    final String input = source.substring(offset, offset + length);
    //    final PHPParserResult result = PHPParser.parse(input);
    //    final String output = format(input, result, indent);
    //    if (output != null) {
    //      if (!input.equals(output)) {
    //        if (!isValidation() || equalsIgnoreBlanks(new StringReader(input), new StringReader(output))) {
    //          return new ReplaceEdit(offset, length, output);
    //        }
    //        else {
    //          PHPFormatterPlugin.log(new Status(IStatus.ERROR, PHPFormatterPlugin.PLUGIN_ID, IStatus.OK,
    //              PHPFormatterMessages.PHPFormatter_contentCorrupted, new DumpContentException(input)));
    //        }
    //      }
    //      else {
    //        return new MultiTextEdit(); // NOP
    //      }
    //    }
    return null;
  }

  protected boolean isValidation() {
    return !getBoolean(PHPFormatterConstants.WRAP_COMMENTS);
  }

  /**
   * @param input
   * @param result
   * @return
   */
  private String format(String input, PHPParserResult result, int indent) {
    //    final PHPFormatterNodeBuilder builder = new PHPFormatterNodeBuilder();
    //    final FormatterDocument document = createDocument(input);
    //    IFormatterContainerNode root = builder.build(result, document);
    //    new PHPFormatterNodeRewriter(result).rewrite(root);
    //    IFormatterContext context = new PHPFormatterContext(indent);
    //    FormatterWriter writer = new FormatterWriter(document, lineDelimiter, createIndentGenerator());
    //    writer.setWrapLength(getInt(PHPFormatterConstants.WRAP_COMMENTS_LENGTH));
    //    writer.setLinesPreserve(getInt(PHPFormatterConstants.LINES_PRESERVE));
    //    try {
    //      root.accept(context, writer);
    //      writer.flush(context);
    //      return writer.getOutput();
    //    }
    //    catch (Exception e) {
    //      e.printStackTrace();
    //      return null;
    //    }
    return null;
  }

  private FormatterDocument createDocument(String input) {
    FormatterDocument document = new FormatterDocument(input);
    for (int i = 0; i < INDENTING.length; ++i) {
      document.setBoolean(INDENTING[i], getBoolean(INDENTING[i]));
    }
    for (int i = 0; i < BLANK_LINES.length; ++i) {
      document.setInt(BLANK_LINES[i], getInt(BLANK_LINES[i]));
    }
    document.setInt(PHPFormatterConstants.FORMATTER_TAB_SIZE, getInt(PHPFormatterConstants.FORMATTER_TAB_SIZE));
    document.setBoolean(PHPFormatterConstants.WRAP_COMMENTS, getBoolean(PHPFormatterConstants.WRAP_COMMENTS));
    return document;
  }

  public static boolean isBooleanOption(String optionName) {
    for (int i = 0; i < INDENTING.length; ++i) {
      if (INDENTING[i].equals(optionName)) {
        return true;
      }
    }
    return false;
  }

  public static boolean isIntegerOption(String optionName) {
    for (int i = 0; i < BLANK_LINES.length; ++i) {
      if (BLANK_LINES[i].equals(optionName)) {
        return true;
      }
    }
    return false;
  }

  private boolean equalsIgnoreBlanks(Reader inputReader, Reader outputReader) {
    LineNumberReader input = new LineNumberReader(inputReader);
    LineNumberReader output = new LineNumberReader(outputReader);
    for (;;) {
      final String inputLine = readLine(input);
      final String outputLine = readLine(output);
      if (inputLine == null) {
        if (outputLine == null) {
          return true;
        }
        else {
          return false;
        }
      }
      else if (outputLine == null) {
        return false;
      }
      else if (!inputLine.equals(outputLine)) {
        return false;
      }
    }
  }

  private String readLine(LineNumberReader reader) {
    String line;
    do {
      try {
        line = reader.readLine();
      }
      catch (IOException e) {
        // should not happen
        return null;
      }
      if (line == null) {
        return line;
      }
      line = line.trim();
    } while (line.length() == 0);
    return line;
  }
}
